using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Collections.Generic;
using System.Web;
using System.Security.Permissions;
using System.Text;
using SharpPieces.Web.JQuery.Design;
using System.Drawing;

[assembly: WebResource("SharpPieces.Web.JQuery.GridViewExtender.flexigrid.js", "text/javascript")]
[assembly: WebResource("SharpPieces.Web.JQuery.GridViewExtender.flexigrid.pack.js", "text/javascript")]
[assembly: WebResource("SharpPieces.Web.JQuery.GridViewExtender.flexigrid.css", "text/css")]

namespace SharpPieces.Web.JQuery
{

    /// <summary>
    /// Represents a GridView extender containing various plugins.
    /// </summary>
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [Designer(typeof(GridViewExtenderDesigner)), Description("GridView extender containing various plugins.")]
    [ToolboxData("<{0}:GridViewExtender runat=\"server\"></{0}:GridViewExtender>"), Themeable(true)]
    [ToolboxBitmap(typeof(GridViewExtender), "GridViewExtender.GridViewExtender.bmp")]
    public class GridViewExtender : BaseJQueryExtender
    {

        // Methods

        /// <summary>
        /// Gets the JQuery object properties.
        /// The key is the object property name.
        /// The value is the object property initial value.
        /// </summary>
        protected override IEnumerable<KeyValuePair<string, object>> GetJQueryObjectProperties()
        {
            yield break;
        }

        /// <summary>
        /// Gets the JQuery object events.
        /// The key is the object event name.
        /// The value is the object event handler.
        /// </summary>
        protected override IEnumerable<KeyValuePair<string, string>> GetJQueryObjectEvents()
        {
            yield break;
        }

        /// <summary>
        /// Gets the JQuery script references.
        /// </summary>
        protected override IEnumerable<ScriptReference> GetJQueryScriptReferences()
        {
#if DEBUG
            if (this.FlexiGrid.Enabled)
            {
                yield return new ScriptReference(
                    this.Page.ClientScript.GetWebResourceUrl(this.GetType(), "SharpPieces.Web.JQuery.GridViewExtender.flexigrid.js"),
                    typeof(GridViewExtender).Assembly.FullName);
            }
#else
            if (this.FlexiGrid.Enabled)
            {
                yield return new ScriptReference(
                    this.Page.ClientScript.GetWebResourceUrl(this.GetType(), "SharpPieces.Web.JQuery.GridViewExtender.flexigrid.pack.js"), 
                    typeof(GridViewExtender).Assembly.FullName);
            }
#endif
        }

        /// <summary>
        /// Gets the client initialization scripts.
        /// The key is the script name and the value is the script.
        /// </summary>
        /// <value>The client initialization scripts.</value>
        protected IEnumerable<KeyValuePair<string, string>> GetClientScriptInitializations()
        {
            GridView target = this.ResolveTargetControl<GridView>();

            Dictionary<string, string> options = new Dictionary<string, string>();

            // height from grid
            if (Unit.Empty != target.Height)
            {
                options["height"] = string.Format("{0}", target.Height.Value);
                target.Height = Unit.Empty;
            }

            // width from grid
            if (Unit.Empty != target.Width)
            {
                options["width"] = string.Format("{0}", target.Width.Value);
                target.Width = Unit.Empty;
            }

            // novstripe new
            // minwidth new
            // minheight new
            // resizable new
            // url hidden
            // method hidden
            // dataType hidden
            // errormsg hidden
            // usepager hidden
            // nowrap new
            // page hidden
            // total hidden
            // useRp hidden
            // rp hidden
            // rpOptions hidden
            // title ?
            // pagestat hidden
            // procmsg hidden
            // query hidden
            // qtype ?
            // nomsg ?
            // minColToggle new
            // showToggleBtn new
            // hideOnSubmit ?
            // autoload ?
            // blockOpacity ?
            // onToggleCol ?
            // onChangeSort ?
            // onSuccess ?
            // onSubmit ?

            return new KeyValuePair<string, string>[] {
                    new KeyValuePair<string, string>(
                        string.Format("{0}InitGridViewExtender", this.TargetControlID),
                        string.Format(
                            "<script type=\"text/javascript\">" + Environment.NewLine + 
                            "t = jQuery.addFlex(jQuery('#{0}'), {1});" + Environment.NewLine +     
                            "jQuery('thead tr:first th',t.grid.hDiv).each(" + Environment.NewLine + 
                            "    function (){{" + Environment.NewLine + 
                            "        var n = jQuery('thead th',t.grid.hDiv).index(this);" + Environment.NewLine + 
                            "        var nw = jQuery('th:visible div:eq('+n+')',this.hDiv).width();" + Environment.NewLine + 
                            "        jQuery('tr',t.grid.bDiv).each (" + Environment.NewLine + 
                            "            function(){{" + Environment.NewLine + 
                            "                jQuery('td:visible div:eq('+n+')',this).css('width',nw);" + Environment.NewLine + 
                            "            }}" + Environment.NewLine + 
                            "        );" + Environment.NewLine + 
                            "    }}" + Environment.NewLine + 
                            ");</script>", 
                            target.ClientID,
                            BaseJQueryExtender.OptionListToJS(options))
                        )
                    };
        }

        /// <summary>
        /// Gets the control style references.
        /// </summary>
        /// <value>The control style references.</value>
        protected override IEnumerable<string> GetClientStyleReferences()
        {
            return new string[] { 
                string.Format("<link href='{0}' rel='stylesheet' type='text/css' />", 
                    this.Page.ClientScript.GetWebResourceUrl(this.GetType(), "SharpPieces.Web.JQuery.GridViewExtender.flexigrid.css"))
                };
        }

        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.PreRender"></see> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"></see> object that contains the event data.</param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            GridView targetGrid = this.ResolveTargetControl<GridView>();

            // fix some grid view render issues

            targetGrid.UseAccessibleHeader = true;

            if (null != targetGrid.HeaderRow)
            {
                targetGrid.HeaderRow.TableSection = TableRowSection.TableHeader;
            }
            //// messes up with the paging
            //if (null != targetGrid.FooterRow)
            //{
            //    targetGrid.FooterRow.TableSection = TableRowSection.TableFooter;
            //}

            targetGrid.GridLines = GridLines.None;
            targetGrid.CellSpacing = -1;
        }


        // Properties

        /// <summary>
        /// Gets or sets the target control ID.
        /// </summary>
        /// <value>The target control ID.</value>
        [TypeConverter(typeof(GridViewControlConverter)) ]
        public override string TargetControlID
        {
            get { return base.TargetControlID; }
            set { base.TargetControlID = value; }
        }


        /// <summary>
        /// Gets or sets the configuration for the FlexiGrid plugin (Paulo Marinas).
        /// </summary>
        /// <value>The configuration for the FlexiGrid plugin (Paulo Marinas).</value>
        [Description("The configuration for the FlexiGrid plugin (Paulo Marinas)."), Category("Plugins"), DefaultValue((string)null), MergableProperty(false), NotifyParentProperty(true)]
        [PersistenceMode(PersistenceMode.InnerProperty), Themeable(false)]
        public virtual FlexiGrid FlexiGrid
        {
            get
            {
                if (null == this.ViewState["FlexiGrid"])
                {
                    FlexiGrid fg = new FlexiGrid();
                    if (this.EnableViewState)
                    {
                        fg.TrackViewState();
                    }
                    this.ViewState["FlexiGrid"] = fg;
                }
                return (FlexiGrid)this.ViewState["FlexiGrid"];
            }
            set
            {
                if ((null != value) && this.EnableViewState)
                {
                    value.TrackViewState();
                }
                this.ViewState["FlexiGrid"] = value;
            }
        }
        
    }


    /// <summary>
    /// Provides a type converter that retrieves a list of control IDs in the current 
    /// container, of the GridView type or convertible.
    /// </summary>
    internal class GridViewControlConverter : ControlIDConverter
    {

        // Methods

        /// <summary>
        /// Returns a value indicating whether the control ID of the specified control is added to the <see cref="T:System.ComponentModel.TypeConverter.StandardValuesCollection"></see> that is returned by the <see cref="M:System.Web.UI.WebControls.ControlIDConverter.GetStandardValues(System.ComponentModel.ITypeDescriptorContext)"></see> method.
        /// </summary>
        /// <param name="control">The control instance to test for inclusion in the <see cref="T:System.ComponentModel.TypeConverter.StandardValuesCollection"></see>.</param>
        /// <returns>true in all cases.</returns>
        protected override bool FilterControl(Control control)
        {
            return typeof(GridView).IsInstanceOfType(control);
        }

    }


    /// <summary>
    /// Represents a FlexiGrid plugin implementation.
    /// </summary>
    [Serializable]
    [TypeConverter(typeof(ExpandableObjectConverter)), DefaultProperty("Enabled")]
    public class FlexiGrid : IStateManager
    {

        // Fields

        private bool tracks;
        private DirtyFlags dirtyFlags = DirtyFlags.None;
        private bool enabled = false;


        // Methods

        /// <summary>
        /// When implemented by a class, gets a value indicating whether a server control is tracking its view state changes.
        /// </summary>
        /// <value></value>
        /// <returns>true if a server control is tracking its view state changes; otherwise, false.</returns>
        internal bool IsTrackingViewState
        {
            get { return this.tracks; }
        }

        /// <summary>
        /// When implemented by a class, loads the server control's previously saved view state to the control.
        /// </summary>
        /// <param name="state">An <see cref="T:System.Object"></see> that contains the saved view state values for the control.</param>
        internal virtual void LoadViewState(object state)
        {
            if (null != state)
            {
                object[] s = state as object[];
                if (null != s[0])
                {
                    this.Enabled = (bool)s[0];
                }
            }
        }

        /// <summary>
        /// When implemented by a class, saves the changes to a server control's view state to an <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// The <see cref="T:System.Object"></see> that contains the view state changes.
        /// </returns>
        internal virtual object SaveViewState()
        {
            object[] state = new object[4];

            state[0] = ((this.dirtyFlags & DirtyFlags.Enabled) == DirtyFlags.Enabled) ? (object)this.Enabled : null;

            return state;
        }

        /// <summary>
        /// When implemented by a class, instructs the server control to track changes to its view state.
        /// </summary>
        internal void TrackViewState()
        {
            this.tracks = true;
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override string ToString()
        {
            return string.Empty;
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"></see> is equal to the current <see cref="T:System.Object"></see>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"></see> to compare with the current <see cref="T:System.Object"></see>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"></see> is equal to the current <see cref="T:System.Object"></see>; otherwise, false.
        /// </returns>
        public override bool Equals(object obj)
        {
            if ((null == obj) || (typeof(FlexiGrid) != obj.GetType()))
            {
                return false;
            }

            FlexiGrid compared = (FlexiGrid)obj;
            return (this.Enabled == compared.Enabled);
        }

        /// <summary>
        /// Serves as a hash function for a particular type. <see cref="M:System.Object.GetHashCode"></see> is suitable for use in hashing algorithms and data structures like a hash table.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }


        // Properties

        /// <summary>
        /// Gets or sets a value indicating whether to enable this plugin.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this plugin should be enabled; otherwise, <c>false</c>.
        /// </value>
        [Description("Indicates whether to enable this plugin."), DefaultValue(false), NotifyParentProperty(true)]
        [PersistenceMode(PersistenceMode.Attribute), Themeable(true)]
        public virtual bool Enabled
        {
            get { return this.enabled; }
            set
            {
                this.enabled = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.Enabled;
                }
            }
        }


        // Nested Types

        private enum DirtyFlags
        {
            None = 0,
            Enabled = 1,
        }

        #region IStateManager Members

        /// <summary>
        /// When implemented by a class, gets a value indicating whether a server control is tracking its view state changes.
        /// </summary>
        /// <value></value>
        /// <returns>true if a server control is tracking its view state changes; otherwise, false.</returns>
        bool IStateManager.IsTrackingViewState
        {
            get { return this.IsTrackingViewState; }
        }

        /// <summary>
        /// When implemented by a class, loads the server control's previously saved view state to the control.
        /// </summary>
        /// <param name="state">An <see cref="T:System.Object"></see> that contains the saved view state values for the control.</param>
        void IStateManager.LoadViewState(object state)
        {
            this.LoadViewState(state);
        }

        /// <summary>
        /// When implemented by a class, saves the changes to a server control's view state to an <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// The <see cref="T:System.Object"></see> that contains the view state changes.
        /// </returns>
        object IStateManager.SaveViewState()
        {
            return this.SaveViewState();
        }

        /// <summary>
        /// When implemented by a class, instructs the server control to track changes to its view state.
        /// </summary>
        void IStateManager.TrackViewState()
        {
            this.TrackViewState();
        }

        #endregion
    }

}
